//#define	_TEST_
#define _PRE_FILTER_
#define _AUTO_DETECT_Q_
#define	_UV_
//#define	GREY_UV
#define StopSize 4

#ifndef _VC10EA_

#include <string.h> 
#include <math.h> 
#include <stdlib.h>
#ifndef	_TI_
#include <malloc.h>
#endif

//#undef _MMX_

#include "cTypes.h"
#include "BitLine.h"
#include "Sort.h"
#include "Codec.h"
#include "DeltaLine.h"
#include "MemManager.h"

#ifdef _MVECTOR_
int FrameCounter = 0;
int TotalPkSize = 0;
int	LevelQ_KeyFrame[100] = {4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4};
int	LevelQ_NotKeyFrame[100] = {4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4};
extern BYTE BlocksMap[]; 
#endif

int	LevelQ_Init[100] = {4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4,
						4, 4, 4, 4, 4,  4, 4, 4, 4, 4};
int Filter_Params_Init[33] = { 01, 50, 00, 00,  00, 00, 00, 00, 
                               00, 00, 00, 00,  00, 00, 00, 00,
                               00, 00, 00, 00,  00, 00, 00, 00,
                               00, 00, 00, 00,  00, 00, 00, 00,
								0x1};

extern short Quantum[512*(MaxQ+1)];
extern short Quantum_Rev[512*(MaxQ+1)];
extern short Quantum_Delta[512*(MaxQ+1)];

void Decompress_Entry(BYTE *buf, BYTE *QuartBuf, int W, int H, BYTE *Pool, int *Start, BYTE *Memory, int BufType, int QUART);

#else //ndef _VC10EA_

#ifdef _MVECTOR_
int FrameCounter;
int TotalPkSize;
int	LevelQ_KeyFrame[100];
int	LevelQ_NotKeyFrame[100];
#endif
int	LevelQ_Init[100];
int Filter_Params_Init[33];

#endif //ndef _VC10EA_

#ifdef _MVECTOR_
#define MaxFrameCounter 300
#define KeyFrameRise 60
BYTE IBufferY[1024*1024*3];	
BYTE IBufferU[512*512*3];	
BYTE IBufferV[512*512*3];	
BYTE IBufferY_dec[1024*1024];	
BYTE IBufferU_dec[512*512];	
BYTE IBufferV_dec[512*512];	
#endif

BYTE CLIP_BYTE [2048];
BYTE CLIP_BYTEN[2048];

void InitClip()
{
	int x;
	for (x=-1024;x<1024;x++) {
		CLIP_BYTE [x+1024]= ((x)<0? 0:(x)>255? 255:(x));
		CLIP_BYTEN[x+1024]=  ((x)<-255? -255:(x)>255? 255:(x));

	}
}

#define MinProbability(Q) ((Q)<=10? 0:((Q)-10 )*30)
//#define MinProbability(Q) 0

//#ifdef	_TEST_
BYTE Temp[1024*1024];
//int TestFrame=0;
//#endif

/*==============================================================================================================

						I N I T --- F R E E												


==============================================================================================================*/

void COMMON_INIT()
{

							InitClip();
							Init_Quantum();
							Init_CNL_Table();
}

#ifdef _TI_
int	 TI_ENCODER_MEMORY_SIZE(int W, int H){ return ENCODER_MEMORY_SIZE(W,H); }
int	 TI_DECODER_MEMORY_SIZE(int W, int H){ return DECODER_MEMORY_SIZE(W,H); }
void TI_ENCODER_MEMORY_INIT(BYTE *Memory, int W, int H)
{ ENCODER_MEMORY_INIT(Memory,W,H); }
void TI_DECODER_MEMORY_INIT(BYTE *Memory, int W, int H)
{ DECODER_MEMORY_INIT(Memory,W,H); }

#else
BYTE *INIT_ENCODER(int W, int H)
{
	BYTE *Memory;
	int SZ = ENCODER_MEMORY_SIZE(W,H);
	Memory = (BYTE*)malloc(SZ);
	ENCODER_MEMORY_INIT(Memory, W, H);
	return Memory;
}
void FREE_ENCODER(void *Memory)
{
	free(Memory);
}


BYTE *INIT_DECODER(int W, int H)
{
	BYTE *Memory;
	int SZ = DECODER_MEMORY_SIZE(W,H); 
	Memory = (BYTE*)malloc(SZ);
	DECODER_MEMORY_INIT(Memory, W, H);
	return Memory;

}

void FREE_DECODER(void *Memory)
{
	free(Memory);
}
#endif



/*==============================================================================================================

						C O M P R E S S												


==============================================================================================================*/

int Top(int Level) {
	if (Level<2)  return 30;
	if (Level==2) return 15;
	if (Level==3) return 15;
	if (Level==4) return 15;
	if (Level==5) return 15;
	return 4;
}



INLINE void PutDelta(BYTE *dest, int V, int Base1, int Base2, int N1, int N2, int N3, int N4, short *Quant, 
					 short *Rest_Delta, int *NewIndex, int *Delta_Pnt, char *QuantDelta, short *Probability)
					 
{
	int BB, Pr;

	BB = Base1+Base2;
	
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	BB=(BB+1)>>1;
		Probability[*Delta_Pnt]= Pr;
		NewIndex[Pr] += 1;	

		V -= BB;
		*dest = CLIP(BB+Rest_Delta[V]);

		QuantDelta[*Delta_Pnt] = Quant[V];
	  	*Delta_Pnt += 1;

}

INLINE void PutDelta_MinProb(BYTE *dest, int V, int Base1, int Base2, int N1, int N2, int N3, int N4, short *Quant, 
						 short *Rest_Delta, int MinProb, int *NewIndex, int *Delta_Pnt, char *QuantDelta, short *Probability)
{
	int BB, Pr;

	BB = Base1+Base2;
	
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	BB=(BB+1)>>1;
	if (Pr>=MinProb) {
		Probability[*Delta_Pnt]= Pr;
		NewIndex[Pr] += 1;

		V -= BB;
		*dest = CLIP(BB+Rest_Delta[V]);

		QuantDelta[*Delta_Pnt] = Quant[V];
	  	*Delta_Pnt += 1;
	} else {
		*dest = BB;
	}		

}


void PutDelta_BaseX(BYTE *buf, BYTE *Top, BYTE *Center, BYTE *Bottom, int W, short *Quant, short *Rest_Delta, 
					int MinProb, int *Delta_Pnt, int *NewIndex_X, char *QuantDelta, short *Probability)
{
	int x;



	if (MinProb==0) {
  //_________________ 

#ifdef _MMX_
		INTEL_PutDelta_BaseX(buf, Top, Center, Bottom, W, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                 &QuantDelta[*Delta_Pnt], NewIndex_X);
		*Delta_Pnt += W>>1;
#else



		for (x=2; x<W; x+=2, Top++, Center++, Bottom++) {

			buf[x-2] = *Center;

			PutDelta(&buf[x-1], (int) buf[x-1], *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], Quant, 
					     Rest_Delta, NewIndex_X, Delta_Pnt, QuantDelta, Probability); 
			
		}

		buf[x-2] = *Center;
		if ((x-1)<W) PutDelta(&buf[x-1], (int) buf[x-1], *Center, *Center, *Top, *Top, *Bottom, *Bottom, Quant, 
				                  Rest_Delta, NewIndex_X, Delta_Pnt, QuantDelta, Probability); 
#endif

	} else {
  //_________________ 
	
#ifdef _MMX_

		INTEL_PutDelta_BaseX_MinProb(buf, Top, Center, Bottom, W, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                         &QuantDelta[*Delta_Pnt], MinProb, Delta_Pnt, NewIndex_X);
#else
			

		for (x=2; x<W; x+=2, Top++, Center++, Bottom++) {
			buf[x-2] = *Center;
			PutDelta_MinProb(&buf[x-1], (int) buf[x-1], *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], Quant, 
				             Rest_Delta, MinProb, NewIndex_X, Delta_Pnt, QuantDelta, Probability); 
		}
		
		buf[x-2] = *Center;
		if ((x-1)<W) PutDelta_MinProb(&buf[x-1], (int) buf[x-1], *Center, *Center, *Top, *Top, *Bottom, *Bottom, 
				                          Quant, Rest_Delta, MinProb, NewIndex_X, Delta_Pnt, QuantDelta, Probability);

#endif

	}
}

void PutDelta_BaseY(BYTE *dest, BYTE *src, BYTE *Top, BYTE *Bottom, int Cnt, short *Quant, short *Rest_Delta, 
					int MinProb, int *Delta_Pnt, int	*NewIndex_Y, char *QuantDelta, short *Probability)
{	
	int x;

	if (MinProb==0) {
  //_________________ 

#ifdef _MMX_
		INTEL_PutDelta_BaseY(dest, src, Top, Bottom, Cnt, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                 &QuantDelta[*Delta_Pnt], NewIndex_Y);
		*Delta_Pnt += Cnt;
#else
		
		PutDelta(dest, *src, *Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], Quant, Rest_Delta, NewIndex_Y, 
				 Delta_Pnt, QuantDelta, Probability); 
		src +=2; Top++; Bottom++; dest++;

		for (x = 1; x<(Cnt-1); x++, src +=2, Top++, Bottom++, dest++) {
			
			PutDelta(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], Quant, Rest_Delta, 
					     NewIndex_Y, Delta_Pnt, QuantDelta, Probability);
		
		}

		PutDelta(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, Quant, Rest_Delta, NewIndex_Y, 
		         Delta_Pnt, QuantDelta, Probability);

#endif		
	} else {
  //_________________ 

#ifdef _MMX_
		INTEL_PutDelta_BaseY_MinProb(dest, src, Top, Bottom, Cnt, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                         &QuantDelta[*Delta_Pnt], MinProb, Delta_Pnt, NewIndex_Y);
#else
			
		PutDelta_MinProb(dest, *src, *Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], Quant, Rest_Delta, MinProb, 
			             NewIndex_Y, Delta_Pnt, QuantDelta, Probability); 
		src +=2; Top++; Bottom++; dest++;

		for (x = 1; x<(Cnt-1); x++, src +=2, Top++, Bottom++, dest++) {
			PutDelta_MinProb(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], Quant, Rest_Delta, 
								 MinProb, NewIndex_Y, Delta_Pnt, QuantDelta, Probability);
		}

		PutDelta_MinProb(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, Quant, Rest_Delta, MinProb, 
			             NewIndex_Y, Delta_Pnt, QuantDelta, Probability);
#endif
	
	}
}


void PutDelta_BaseX_MVector(BYTE *buf, BYTE *Top, BYTE *Center, BYTE *Bottom, int W, short *Quant, short *Rest_Delta, 
					int MinProb, int *Delta_Pnt, int *NewIndex_X, char *QuantDelta, short *Probability,
					int BlocksMapIndex, int BMStep, BYTE *BlocksMap)
{
	int x, Pos, RealX=BMStep/2;



	if (MinProb==0) {
  //_________________ 

#ifdef _MMX1_
		INTEL_PutDelta_BaseX(buf, Top, Center, Bottom, W, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                 &QuantDelta[*Delta_Pnt], NewIndex_X);
		*Delta_Pnt += W>>1;
#else

		

		for (x=2; x<W; x+=2, Top++, Center++, Bottom++, RealX+=BMStep) {

			buf[x-2] = *Center;
			
			Pos = BlocksMapIndex +( RealX>>3); 
		    if (!GetBit(BlocksMap, Pos)) 
				PutDelta(&buf[x-1], (int) buf[x-1], *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], Quant, 
					     Rest_Delta, NewIndex_X, Delta_Pnt, QuantDelta, Probability); 
			
		}

			
		buf[x-2] = *Center;
		if ((x-1)<W) {			
			Pos = BlocksMapIndex +( RealX>>3); 
		    if (!GetBit(BlocksMap, Pos)) 
				PutDelta(&buf[x-1], (int) buf[x-1], *Center, *Center, *Top, *Top, *Bottom, *Bottom, Quant, 
				                  Rest_Delta, NewIndex_X, Delta_Pnt, QuantDelta, Probability); 
		}
#endif

	} else {
  //_________________ 
	
#ifdef _MMX1_

		INTEL_PutDelta_BaseX_MinProb(buf, Top, Center, Bottom, W, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                         &QuantDelta[*Delta_Pnt], MinProb, Delta_Pnt, NewIndex_X);
#else
			

		for (x=2; x<W; x+=2, Top++, Center++, Bottom++, RealX+=BMStep) {
			buf[x-2] = *Center;

			Pos = BlocksMapIndex +( RealX>>3); 
		    if (!GetBit(BlocksMap, Pos)) 
				PutDelta_MinProb(&buf[x-1], (int) buf[x-1], *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], Quant, 
				             Rest_Delta, MinProb, NewIndex_X, Delta_Pnt, QuantDelta, Probability); 
		}
		
		buf[x-2] = *Center;
		if ((x-1)<W) {
			Pos = BlocksMapIndex +( RealX>>3); 
		    if (!GetBit(BlocksMap, Pos)) 
				PutDelta_MinProb(&buf[x-1], (int) buf[x-1], *Center, *Center, *Top, *Top, *Bottom, *Bottom, 
					                          Quant, Rest_Delta, MinProb, NewIndex_X, Delta_Pnt, QuantDelta, Probability);

		}
#endif

	}
}

void PutDelta_BaseY_MVector(BYTE *dest, BYTE *src, BYTE *Top, BYTE *Bottom, int Cnt, short *Quant, short *Rest_Delta, 
					int MinProb, int *Delta_Pnt, int	*NewIndex_Y, char *QuantDelta, short *Probability,
					int BlocksMapIndex, int BMStep, BYTE *BlocksMap)
{	
	int x, Pos, RealX=0;

	if (MinProb==0) {
  //_________________ 

#ifdef _MMX1_
		INTEL_PutDelta_BaseY(dest, src, Top, Bottom, Cnt, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                 &QuantDelta[*Delta_Pnt], NewIndex_Y);
		*Delta_Pnt += Cnt;
#else
		
		Pos = BlocksMapIndex +( RealX>>3); 
	    if (!GetBit(BlocksMap, Pos)) 
			PutDelta(dest, *src, *Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], Quant, Rest_Delta, NewIndex_Y, 
					 Delta_Pnt, QuantDelta, Probability); 
		else *dest=*src;
		src +=2; Top++; Bottom++; dest++; RealX+=BMStep;

		for (x = 1; x<(Cnt-1); x++, src +=2, Top++, Bottom++, dest++, RealX+=BMStep) {
			Pos = BlocksMapIndex +( RealX>>3); 
		    if (!GetBit(BlocksMap, Pos)) 
				PutDelta(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], Quant, Rest_Delta, 
					     NewIndex_Y, Delta_Pnt, QuantDelta, Probability);
			else *dest=*src;
		}

		Pos = BlocksMapIndex +( RealX>>3); 
	    if (!GetBit(BlocksMap, Pos)) 
			PutDelta(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, Quant, Rest_Delta, NewIndex_Y, 
			         Delta_Pnt, QuantDelta, Probability);
		else *dest=*src;

#endif		
	} else {
  //_________________ 

#ifdef _MMX1_
		INTEL_PutDelta_BaseY_MinProb(dest, src, Top, Bottom, Cnt, Quant, Rest_Delta, &Probability[*Delta_Pnt], 
			                         &QuantDelta[*Delta_Pnt], MinProb, Delta_Pnt, NewIndex_Y);
#else
			
		Pos = BlocksMapIndex +( RealX>>3); 
	    if (!GetBit(BlocksMap, Pos)) 
			PutDelta_MinProb(dest, *src, *Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], Quant, Rest_Delta, MinProb, 
			             NewIndex_Y, Delta_Pnt, QuantDelta, Probability); 
		else *dest=*src;
		src +=2; Top++; Bottom++; dest++; RealX+=BMStep;

		for (x = 1; x<(Cnt-1); x++, src +=2, Top++, Bottom++, dest++, RealX+=BMStep) {
			Pos = BlocksMapIndex +( RealX>>3); 
		    if (!GetBit(BlocksMap, Pos)) 
				PutDelta_MinProb(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], Quant, Rest_Delta, 
								 MinProb, NewIndex_Y, Delta_Pnt, QuantDelta, Probability);
			else *dest=*src;
		}

		Pos = BlocksMapIndex +( RealX>>3); 
	    if (!GetBit(BlocksMap, Pos)) 
			PutDelta_MinProb(dest, *src, *Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, Quant, Rest_Delta, MinProb, 
			             NewIndex_Y, Delta_Pnt, QuantDelta, Probability);
		else *dest=*src;
#endif
	
	}
}


void CorrectQ(int ToLevel, double FreePkSize, int *LevelQ)
{
	int i;

#ifdef	_AUTO_DETECT_Q_
	if (FreePkSize<0) {

		for (i=0; i<=ToLevel; i++) {
			LevelQ[i]=Top(i);
		}	


	} 
#endif

}

void GlobalCorrectQ(double FreePkSize, int *LevelQ)
{
	int i, d, dd, Sum;
	int Min_d = 2;

#ifdef	_AUTO_DETECT_Q_
	if (FreePkSize<0) {

		d =  Min_(Min_d ,(-FreePkSize)*50);
		

		for (i=0; i<6; i++) {
			if (d==0) break;
			
			dd = Min_(d, Top(i)-LevelQ[i]);
			LevelQ[i] +=dd; 
			d-=dd;
		}	

	} else {
	
		d =  Min_(Min_d ,FreePkSize*50);

		for (i=5; i>=0; i--) {
			
			if (d==0) break;
			
			dd = Min_(d, LevelQ[i]-4);
			LevelQ[i] -=dd; 
			d-=dd;
			
			if (LevelQ[i]>4) { LevelQ[i] -=1; break; }
			
		}	
	}

	
	Sum = LevelQ[2] + LevelQ[3] + LevelQ[4] + LevelQ[5] - 16;
	LevelQ[5] = Max_(0,(Sum-6)/4 - 3) + 4;
	
	Sum -= LevelQ[5] - 4;
	LevelQ[4] = Max_(0,(Sum-3)/3 - 2) + 4;

	Sum -= LevelQ[4] - 4;
	LevelQ[3] = Max_(0,(Sum-1)/2 - 1) + 4;

	Sum -= LevelQ[3] - 4;
	LevelQ[2] = Sum + 4;
#endif

}
/*______________________________________________________________________________________________________________


						Compress_Level

_______________________________________________________________________________________________________________*/



void Compress_Level(BYTE *buf, BYTE *QuartBuf, int W, int H, BYTE *Pool, int *Start,  
					int Level, double PkSize, int QCorrection, int *Start0, BYTE *Memory)
{
	int i, y, x, DPX, DPY, hH, hW, Qshift, DPXo, Qx, MinPX, MinPY;
	BYTE	*PB, *QB, *LL;
	int BlocksMapPnt, BMStep;

	int *LevelQ			= (int*)   ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_LevelQ,	  Memory);
	int *NewIndex_X		= (int*)   ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_NewIndex_X,  Memory);
	int *NewIndex_Y		= (int*)   ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_NewIndex_Y,  Memory);
	char *QuantDelta	= (char*)  ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_QuantDelta,  Memory);
	short *Probability  = (short*) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Probability, Memory);
	BYTE *L1			=          ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line1,  Memory); 
	BYTE *L2			=          ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line2,  Memory); 



	if ((H <= StopSize) || (W <= StopSize)) {
		for (i = 0; i<H*W; i++) PutNumber((int)buf[i], 0xFF, Pool, Start);
		return;
	}



	QB = QuartBuf;
	hH = (H+1)>>1; hW = (W+1)>>1;
	for (y=0; y<H; y+=2) {
		PB = buf+W*y; 
		for (x=0; x<hW; x++, PB+=2) *QB++ = *PB; 
	}


				
	
	Compress_Level(QuartBuf, QB, hW, hH, Pool, Start, Level+2, PkSize, QCorrection, Start0, Memory);





	DPXo = (H-hH) * hW;
	DPY = 0; DPX = DPXo; QB = QuartBuf; PB = buf; 
	MinPX=0; MinPY=0;
	if (Level==0) { 
		MinPX = MinProbability(LevelQ[Level]); 
		MinPY = MinProbability(LevelQ[Level+1]); 
	}

	for (y=0; y<H; y+=2, PB+=W*2, QB+=hW) {
		


		if ((y+1)<H) {
			Qshift = (LevelQ[Level+1]<<9)+255;
			
			if ((y+2)<H) PutDelta_BaseY(L2, PB+W, QB, QB+hW, hW, Quantum+Qshift, Quantum_Delta+Qshift, MinPY, &DPY, 
				                        NewIndex_Y, QuantDelta, Probability); 
			else PutDelta_BaseY(L2, PB+W, QB, QB, hW, Quantum+Qshift, Quantum_Delta+Qshift, MinPY, &DPY, 
				                NewIndex_Y, QuantDelta, Probability);
			
		}

		Qshift = (LevelQ[Level]<<9)+255;


		if (y==0) PutDelta_BaseX(PB, QB, QB, L2, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
			                     NewIndex_X, QuantDelta, Probability); 
		else { 
			if ((y+1)<H) PutDelta_BaseX(PB, L1, QB, L2, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                        NewIndex_X, QuantDelta, Probability);
			else PutDelta_BaseX(PB, L1, QB, QB, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                NewIndex_X, QuantDelta, Probability);
		}

		
		if ((y+1)<H) {
			if ((y+2)<H) PutDelta_BaseX(PB+W, QB, L2, QB+hW, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                        NewIndex_X, QuantDelta, Probability); 
			else PutDelta_BaseX(PB+W, QB, L2, L2,    W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                NewIndex_X, QuantDelta, Probability);	
			
		}


		LL = L1; L1 = L2; L2 = LL; // swap L1<->L2
	}

	PutNumber(LevelQ[Level+1], MaxQ, Pool, Start);
	if (DPY>0) Sort_Pack_Deltas(QuantDelta,Probability,DPY, LevelQ[Level+1], Pool, Start, NewIndex_Y, Memory);	// Y Base				
	Qx = LevelQ[Level];
	if (QCorrection) CorrectQ(Level, PkSize - (*Start-*Start0), LevelQ);

	PutNumber(Qx, MaxQ, Pool, Start);
	if ((DPX-DPXo)>0) Sort_Pack_Deltas(&QuantDelta[DPXo],&Probability[DPXo],DPX-DPXo, Qx, Pool, Start, NewIndex_X, 
																							Memory);			// X Base
	if (QCorrection) CorrectQ(Level-1, PkSize - (*Start-*Start0), LevelQ);



}

/*______________________________________________________________________________________________________________


						Compress_Level_MVector

_______________________________________________________________________________________________________________*/
#ifdef _MVECTOR_

void Compress_Level_MVector(BYTE *buf, BYTE *QuartBuf, int W, int Wo, int H, BYTE *Pool, int *Start,  
					int Level, double PkSize, int QCorrection, int *Start0, BYTE *Memory)
{
	int i, y, x, DPX, DPY, hH, hW, Qshift, DPXo, Qx, MinPX, MinPY;
	BYTE	*PB, *QB, *LL;
	int BlocksMapPnt, BMStep, Pos, RealX;

	int *LevelQ			= (int*)   ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_LevelQ,	  Memory);
	int *NewIndex_X		= (int*)   ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_NewIndex_X,  Memory);
	int *NewIndex_Y		= (int*)   ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_NewIndex_Y,  Memory);
	char *QuantDelta	= (char*)  ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_QuantDelta,  Memory);
	short *Probability  = (short*) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Probability, Memory);
	BYTE *L1			=          ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line1,  Memory); 
	BYTE *L2			=          ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line2,  Memory); 



	if ((H <= StopSize) || (W <= StopSize)) {
		for (y=0; y<H; y++) {
			BMStep = 1<<(Level>>1); BlocksMapPnt = ((y<<(Level>>1))>>3)*((Wo+7)>>3); 
			RealX = 0;
			for (x=0; x<W; x++, RealX+=BMStep, buf++) {

				Pos = BlocksMapPnt +( RealX>>3); 
				if (!GetBit(BlocksMap, Pos)) PutNumber(*buf, 0xFF, Pool, Start);


			}

		}
		return;
	}



	QB = QuartBuf;
	hH = (H+1)>>1; hW = (W+1)>>1;
	for (y=0; y<H; y+=2) {
		PB = buf+W*y; 
		for (x=0; x<hW; x++, PB+=2) *QB++ = *PB; 
	}

	Compress_Level_MVector(QuartBuf, QB, hW, Wo, hH, Pool, Start, Level+2, PkSize, QCorrection, Start0, Memory);





	DPXo = (H-hH) * hW;
	DPY = 0; DPX = DPXo; QB = QuartBuf; PB = buf; 
	MinPX=0; MinPY=0;
	if (Level==0) { 
		MinPX = MinProbability(LevelQ[Level]); 
		MinPY = MinProbability(LevelQ[Level+1]); 
	}

	for (y=0; y<H; y+=2, PB+=W*2, QB+=hW) {
		

		// Odd y
		BMStep = 2<<(Level>>1); BlocksMapPnt = (((y+1)<<(Level>>1))>>3)*((Wo+7)>>3); 

		if ((y+1)<H) {
			Qshift = (LevelQ[Level+1]<<9)+255;
			
			if ((y+2)<H) PutDelta_BaseY_MVector(L2, PB+W, QB, QB+hW, hW, Quantum+Qshift, Quantum_Delta+Qshift, MinPY, 
								&DPY, NewIndex_Y, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap); 
			else PutDelta_BaseY_MVector(L2, PB+W, QB, QB, hW, Quantum+Qshift, Quantum_Delta+Qshift, MinPY, &DPY, 
				                NewIndex_Y, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap);
			
		}

		Qshift = (LevelQ[Level]<<9)+255;

		// Even y - Odd x
		BMStep = 2<<(Level>>1); BlocksMapPnt = ((y<<(Level>>1))>>3)*((Wo+7)>>3); 

		if (y==0) PutDelta_BaseX_MVector(PB, QB, QB, L2, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
			                     NewIndex_X, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap); 
		else { 
			if ((y+1)<H) PutDelta_BaseX_MVector(PB, L1, QB, L2, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                        NewIndex_X, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap);
			else PutDelta_BaseX_MVector(PB, L1, QB, QB, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                NewIndex_X, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap);
		}

		
		// Odd y - Odd x
		BMStep = 2<<(Level>>1); BlocksMapPnt = (((y+1)<<(Level>>1))>>3)*((Wo+7)>>3);  
		if ((y+1)<H) {
			if ((y+2)<H) PutDelta_BaseX_MVector(PB+W, QB, L2, QB+hW, W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                        NewIndex_X, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap); 
			else PutDelta_BaseX_MVector(PB+W, QB, L2, L2,    W, Quantum+Qshift, Quantum_Delta+Qshift, MinPX, &DPX, 
				                NewIndex_X, QuantDelta, Probability, BlocksMapPnt, BMStep, BlocksMap);	
			
		}


		LL = L1; L1 = L2; L2 = LL; // swap L1<->L2
	}

	PutNumber(LevelQ[Level+1], MaxQ, Pool, Start);
	if (DPY>0) Sort_Pack_Deltas(QuantDelta,Probability,DPY, LevelQ[Level+1], Pool, Start, NewIndex_Y, Memory);	// Y Base				
	Qx = LevelQ[Level];
	if (QCorrection) CorrectQ(Level, PkSize - (*Start-*Start0), LevelQ);

	PutNumber(Qx, MaxQ, Pool, Start);
	if ((DPX-DPXo)>0) Sort_Pack_Deltas(&QuantDelta[DPXo],&Probability[DPXo],DPX-DPXo, Qx, Pool, Start, NewIndex_X, 
																							Memory);			// X Base
	if (QCorrection) CorrectQ(Level-1, PkSize - (*Start-*Start0), LevelQ);



}
#endif


void Compress_Entry(BYTE *buf, BYTE *QuartBuf, int W, int H, BYTE *Pool, int *Start,  
					double PkSize, BYTE *Memory, int BufType)
{
	int Start0 = *Start;

#ifdef _MVECTOR_
	BYTE *PrevBuf;
	int i;
	BYTE *Aver, *P;

	if (BufType==0) PrevBuf = IBufferY; 
	if (BufType==1) PrevBuf = IBufferU; 
	if (BufType==2) PrevBuf = IBufferV;


	
	if (FrameCounter==0) {
		memcpy(PrevBuf, buf, W*H);
		P = PrevBuf;   		Aver = PrevBuf + W*H;
		for (i=0; i<W*(H-1); i++, Aver++, P++) *Aver=AVER4(P[0], P[1], P[W], P[W+1]); 

		Compress_Level(buf, QuartBuf, W, H, Pool, Start, 0, PkSize, BufType==0, &Start0, Memory);
		memcpy(PrevBuf+W*H*2, buf, W*H);

		

		
	} else { 
	
		Find_Blocks(PrevBuf, buf, W, H, Pool, Start, BufType, Memory);
		P = PrevBuf;   		Aver = PrevBuf + W*H;
		for (i=0; i<W*(H-1); i++, Aver++, P++) *Aver=AVER4(P[0], P[1], P[W], P[W+1]); 
		Compress_Level_MVector(buf, QuartBuf, W, W, H, Pool, Start, 0, PkSize, BufType==0, &Start0, Memory);
		memcpy(PrevBuf+W*H*2, buf, W*H);
		
	}

		
	


#else

#ifdef	_AVALON_
	{ int St = *Start, i,j;
		memcpy(Temp,buf,W*H);
		ENCODER_2D(buf, W, H, Pool, Start);
#ifdef	_TEST_DECODER_		
		DECODER_2D(buf, W, H, Pool, &St);
		if (*Start!=St) {
			_asm	HLT
		} 
#endif
		
		/*
		for (i=0; i<H; i++) { 
			for (j=0; j<W; j++) {
				if (Temp[W*i+j]!=buf[W*i+j]) {
					_asm	HLT
				}
			}
		} */
		
		
	}

#else
	Compress_Level(buf, QuartBuf, W, H, Pool, Start, 0, PkSize, BufType==0, &Start0, Memory);
#endif


#endif	

}



void H_Filter(BYTE *buf, int W, int H)
{
#ifdef	_MMX_
	{
	int y;
	
	for (y=0; y<(H-1); y++, buf+=W) INTEL_Aver_Line(buf, buf, buf+W, W);	
	}
#else
{
	int y, x;
	BYTE *L1, *L2;

	for (y=0; y<(H-1); y++) {
		x = W;
		L1 = buf + y*W; L2 = L1+W;
		while (x--) { *L1 = ((int) *L1 + *L2++ +1)>>1; L1++; }
	}

}
#endif
}


void P_Filter(BYTE *buf, int W, int H, BYTE *Memory)
{

	int CenterScale;

	CenterScale = Read_Filter_Param(0, Memory);
	if (CenterScale>15) return;

#ifdef	_MMX_

	INTEL_P_Filter(buf, W, H, CenterScale);

#else

	{
	
	int K;
	int y, x;
	BYTE *L1, *L2, *L3;

	BYTE *T1 = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line1,  Memory); 
	BYTE *T2 = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line2,  Memory); 




	K=0x10000/(4+CenterScale);

	L1 = T1+1; L2 = T2+1;
	
    for (x=0; x<W; x++) L1[x] = buf[x]; 

	for (y = 0; y<(H-1); y++, buf+=W) {

		for (x=0; x<W; x++) L2[x] = buf[x]; 
		L2[-1] = L2[0]; L2[W] = L2[W-1];
		
		for (x=0; x<W; x++) {
			buf[x] = ((CenterScale*((int)L2[x]) + (int)L2[x-1] + (int)L2[x+1] + (int)L1[x] + (int)buf[W+x])*K)>>16; 
		}

		L3=L1; L1=L2; L2=L3;
	}


	for (x=0; x<W; x++) L2[x] = buf[x]; 
	L2[-1] = L2[0]; L2[W] = L2[W-1];
		
	for (x=0; x<W; x++) {
		buf[x] = (( CenterScale*((int)L2[x]) + (int)L2[x-1] + (int)L2[x+1] + (int)L1[x] + (int)L2[x])*K)>>16; 
	}





	}
#endif
}

void Write_Filter_Param(int Param, int Index, BYTE *Memory) {

	int  *FP = (int *) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Filter_Params, Memory);
	
	FP[Index & 0x1F] = Param;
}
int Read_Filter_Param(int Index, BYTE *Memory) {

	int  *FP = (int *) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Filter_Params, Memory);
	
	return FP[Index & 0x1F];
}
void Write_Filter_Mask(unsigned int Mask, BYTE *Memory) {

	unsigned int  *FP = (unsigned int *) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Filter_Params, Memory);
	
	FP[0x20] = Mask;
}
unsigned int Read_Filter_Mask(BYTE *Memory) {

	unsigned int  *FP = (unsigned int *) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Filter_Params, Memory);
	
	return FP[0x20];
}


void Extrem_Filter_Aver(BYTE *buf, int W, int H, BYTE *Memory)
{
	int  Max_Min;

	Max_Min = Read_Filter_Param(1, Memory); 


#ifdef	_MMX_

	INTEL_Extrem_Filter_Aver(buf, W, H, Max_Min);

#else
	{

	int y, x, i;
	BYTE *L1, *L2, *L3;
	int Min[4], Max[4], Aver;

	BYTE *T1 = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line1,    Memory); 
	BYTE *T2 = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line2,    Memory); 


	L1 = T1; L2 = T2;
	
    for (x=0; x<W; x++) L1[x] = buf[x]; 

	for (y = 0; y<H; y++, buf+=W) {

		for (x=0; x<W; x++) L2[x] = buf[x]; 
		if (y==(H-1)) L3 = L2; else L3 = buf+W;


		for (x=1; x<(W-1); x++) {
			for (i=0; i<3; i++) {
				Min[i] = Min_(L1[x-1+i],L3[x-1+i]);
				Max[i] = Max_(L1[x-1+i],L3[x-1+i]);
			}
			Min[3] = Min_(L2[x-1],L2[x+1]);
			Max[3] = Max_(L2[x-1],L2[x+1]);
			Min[0] = Min_( Min_(Min[0],Min[1]), Min_(Min[2],Min[3]) );
			Max[0] = Max_( Max_(Max[0],Max[1]), Max_(Max[2],Max[3]) );

			
			Aver = ( (((int) L2[x-1] + (int) L2[x+1] +1)>>1) + 
				     (((int) L1[x] +   (int) L3[x]   +1)>>1) + 1 )>>1;

			if ((Max[0]-Min[0])>=Max_Min) {
				if ((buf[x]<=Min[0]) || (buf[x]>=Max[0])) buf[x] = (Aver + buf[x] + 1)>>1;
			} else {
				if ((buf[x]<=Min[0]) || (buf[x]>=Max[0])) buf[x] = Aver;
			}
		}


		L3=L1; L1=L2; L2=L3;
	}

	
	
}
#endif

}

void Extrem_Filter_MinMax(BYTE *buf, int W, int H, BYTE *Memory)
{

#ifdef	_MMX_

	INTEL_Extrem_Filter_MinMax(buf, W, H);

#else
	{



	int y, x, i;
	BYTE *L1, *L2, *L3;
	int Min[4], Max[4];





	BYTE *T1 = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line1,  Memory); 
	BYTE *T2 = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Temp_Line2,  Memory); 



	L1 = T1; L2 = T2;
	
    for (x=0; x<W; x++) L1[x] = buf[x]; 

	for (y = 0; y<H; y++, buf+=W) {

		for (x=0; x<W; x++) L2[x] = buf[x]; 
		if (y==(H-1)) L3 = L2; else L3 = buf+W;


		for (x=1; x<(W-1); x++) {



			for (i=0; i<3; i++) {
				Min[i] = Min_(L1[x-1+i],L3[x-1+i]);
				Max[i] = Max_(L1[x-1+i],L3[x-1+i]);
			}
			Min[3] = Min_(L2[x-1],L2[x+1]);
			Max[3] = Max_(L2[x-1],L2[x+1]);
			Min[0] = Min_( Min_(Min[0],Min[1]), Min_(Min[2],Min[3]) );
			Max[0] = Max_( Max_(Max[0],Max[1]), Max_(Max[2],Max[3]) );

			
			if (buf[x]<Min[0]) buf[x]=Min[0];
			else if (buf[x]>Max[0]) buf[x]=Max[0];
			


		}


		L3=L1; L1=L2; L2=L3;
	}




	}
#endif
}




void Filter(BYTE *buf, int W, int H, int UV, BYTE *Memory, unsigned int FilterSet)
{
	
#ifdef _PRE_FILTER_
	if (FilterSet & 8) H_Filter(buf, W, H);							// Index = 3
	if (FilterSet & 4) Extrem_Filter_MinMax(buf, W, H, Memory);		// Index = 2
	if (FilterSet & 2) Extrem_Filter_Aver(buf, W, H, Memory);		// Index = 1
	if (FilterSet & 1) P_Filter(buf, W, H, Memory);					// Index = 0

#endif

}





void Compress_UV(BYTE *buf, BYTE *QuartBuf, int W, int H, BYTE *Pool, int *Start, int DontRestoreLevel0, 
				 int PkSize, BYTE *Memory, int BufType, unsigned int FilterSet)
{
	int x, y, A;
	BYTE *P, *T;
	int Start0=*Start;

	T = QuartBuf;
	for (y = 0; y<(H-1); y+=2) {
		P = buf+y*W;
		for (x = 0; x<W; x++, P++) {
			A = ((int) *P + P[W] + 1)>>1;
			*T++ = A; 
		}
	}

	Filter(QuartBuf, W, H/2, 1, Memory, FilterSet);
	Compress_Entry(QuartBuf, T, W, H/2, Pool, Start, PkSize, Memory, BufType);

	if (DontRestoreLevel0) return;

	T = QuartBuf;
	for (y = 0; y<(H-1); y+=2) {
		P = buf+y*W;
		for (x = 0; x<W; x++, P++) {
			A = *T++;
#ifdef	GREY_UV			
			A = 128;
#endif
			*P = A; P[W] = A;
		}
	}

}



void Put24(int N, BYTE *Pool, int *Start)
{	int i;
	for (i=0; i<24; i++) {
		if (N&1) SetBit(Pool, *Start); else  ClrBit(Pool, *Start);
		*Start+=1;
		N>>=1;
	}
}

int Get24(BYTE *Pool, int *Start)
{	int i, M=1, N=0;
	for (i=0; i<24; i++) {
		if (GetBit(Pool,*Start)) N |= M;
		*Start+=1;
		M<<=1;
	}

	return N;
}


int COMPRESS_FRAME(BYTE *Ybuf, BYTE *Ubuf, BYTE* Vbuf, int W, int H, BYTE *Pool, int PkSize,  
				   int DontRestoreLevel0, BYTE *Memory)
{

	int Pool_index=0, Pool_indexU, Pool_indexV;
	double PkSize8Y, PkSize8UV, PkSize1;
	const double div = 20;
	unsigned int FilterSet;


	int *LevelQ		   = (int*) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_LevelQ,		Memory);
	BYTE *Quart_Buffer =        ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Quart_Buffer, Memory);

	//return;

	FilterSet = Read_Filter_Mask(Memory);

#ifdef _MVECTOR_
	if (FrameCounter==0) {

		PkSize *= (float) MaxFrameCounter*KeyFrameRise/(KeyFrameRise + MaxFrameCounter -1);
		memcpy(LevelQ, LevelQ_KeyFrame, sizeof(LevelQ_Init));

	} else {
		
		PkSize = ((float) MaxFrameCounter * PkSize - TotalPkSize)/(MaxFrameCounter-FrameCounter);
		memcpy(LevelQ, LevelQ_NotKeyFrame, sizeof(LevelQ_Init));

	}
	
#endif


	PkSize1=PkSize;



	PkSize8Y  = PkSize1 * 8 * (div-2)/div;
	PkSize8UV = PkSize1 * 8   /div;



	Filter(Ybuf, W, H, 0, Memory, FilterSet);
	Compress_Entry(Ybuf, Quart_Buffer, W, H, Pool, &Pool_index, PkSize8Y, Memory, 0);

#ifdef	_TEST_
	{
		int PI=0, i, j;
		BYTE *DecMemory;
		DecMemory = INIT_DECODER(W, H);
		Decompress_Entry(Temp, Quart_Buffer, W, H, Pool, &PI, DecMemory, 0, 0);
		FREE_DECODER(DecMemory);
		for (i=0; i<H; i++) { 
			for (j=0; j<W; j++) {
				if (Temp[W*i+j]!=Ybuf[W*i+j]) {
#ifdef	_TI_
					PI = 0;
#else	
					_asm	HLT
#endif

				}
			}
		}
	}
	//TestFrame++;
#endif

#ifdef	_UV_
	  

	Pool_indexU = Pool_index; 
	Compress_UV(Ubuf, Quart_Buffer, W/2, H, Pool, &Pool_index, DontRestoreLevel0, PkSize8UV, Memory, 1, FilterSet);

	Pool_indexV = Pool_index; 
	Compress_UV(Vbuf, Quart_Buffer, W/2, H, Pool, &Pool_index, DontRestoreLevel0, PkSize8UV, Memory, 2, FilterSet);
	
#endif

	Pool_index = ((Pool_index+7)>>3)<<3;

	Put24(Pool_indexU, Pool, &Pool_index); 
	Put24(Pool_indexV, Pool, &Pool_index); 


	PkSize = Pool_index>>3;


	/*
	{
		BYTE *DecMemory;
		DecMemory = INIT_DECODER(W, H);
		DECOMPRESS_QUART_FRAME(Ybuf, Ubuf, Vbuf, W, H, Pool, DecMemory, 0);
		FREE_DECODER(DecMemory);

	}
	*/


	if (PkSize1>0) GlobalCorrectQ((double) (PkSize1-PkSize)/PkSize1, LevelQ);

#ifdef _MVECTOR_

	if (FrameCounter==0) memcpy(LevelQ_KeyFrame, LevelQ, sizeof(LevelQ_Init));
	else memcpy(LevelQ_NotKeyFrame, LevelQ, sizeof(LevelQ_Init));
	
	TotalPkSize += PkSize;
	FrameCounter = (FrameCounter+1) % MaxFrameCounter;
	if (FrameCounter==0) TotalPkSize=0;

	
#endif
	return PkSize;
}



//==============================================================================================================
//
//						D E C O M P R E S S												
//
//
//==============================================================================================================


INLINE void SetProbability_Y(int Base1, int Base2, int N1, int N2, int N3, int N4, int *Delta_Pnt, int *NewIndex_Y, 
							 short *Probability)
{
	int BB, Pr;

	BB = Base1+Base2;
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	Probability[*Delta_Pnt] = Pr;
	*Delta_Pnt +=1;
	NewIndex_Y[Pr]+=1;

}

INLINE void SetProbability_YLevel1(int Base1, int Base2, int N1, int N2, int N3, int N4, int MinProb, int *Delta_Pnt, 
								   int Prob_Pnt, int *NewIndex_Y, short *Probability, int *ProbLocation)
{
	int BB, Pr;

	BB = Base1+Base2;
	
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	if (Pr>=MinProb) {
		ProbLocation[*Delta_Pnt] = Prob_Pnt;
		Probability[*Delta_Pnt]= Pr;
		*Delta_Pnt +=1;
		NewIndex_Y[Pr] += 1;
	}		

}


INLINE void SetProbability_Y_MVector(int Base1, int Base2, int N1, int N2, int N3, int N4, int *Delta_Pnt, 
								     int Prob_Pnt, int *NewIndex_Y, short *Probability, int *ProbLocation)
{
	int BB, Pr;

	BB = Base1+Base2;
	
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	
		ProbLocation[*Delta_Pnt] = Prob_Pnt;
		Probability[*Delta_Pnt]= Pr;
		*Delta_Pnt +=1;
		NewIndex_Y[Pr] += 1;

}





void SetProb_BaseY(BYTE *Top, BYTE *Bottom, int Cnt, int MinProb, int *Delta_Pnt, int *Prob_Pnt, int *NewIndex_Y, 
				   short *Probability, int *ProbLocation)
{
	int x;

	if (MinProb==0) {
    //______________
#ifdef _MMX_

		INTEL_SetProb_BaseY(Top, Bottom, Cnt, &Probability[*Delta_Pnt], NewIndex_Y); 
		*Delta_Pnt+=Cnt;
#else

		SetProbability_Y(*Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], Delta_Pnt, NewIndex_Y, Probability); 
		Top++; Bottom++; 
	
		for (x=1; x<(Cnt-1); x++, Top++, Bottom++) 
			SetProbability_Y(*Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], Delta_Pnt, NewIndex_Y, Probability);

		SetProbability_Y(*Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, Delta_Pnt, NewIndex_Y, Probability);
#endif

	} else {
   //______________

#ifdef _MMX_

		INTEL_SetProb_BaseY_MinProb(Top, Bottom, Cnt, &Probability[*Delta_Pnt], 
			                         &ProbLocation[*Delta_Pnt], MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_Y);
		*Prob_Pnt+=Cnt;
#else

		SetProbability_YLevel1(*Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_Y,
							  	Probability, ProbLocation); 
		Top++; Bottom++; *Prob_Pnt +=1;
	
		for (x=1; x<(Cnt-1); x++, Top++, Bottom++, *Prob_Pnt +=1) 
			SetProbability_YLevel1(*Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], MinProb, Delta_Pnt, 
									*Prob_Pnt, NewIndex_Y, Probability, ProbLocation);

		SetProbability_YLevel1(*Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_Y,
			                   Probability, ProbLocation);
		*Prob_Pnt +=1;

#endif

	}
}


void SetProb_BaseY_MVector(BYTE *Top, BYTE *Bottom, int Cnt, int MinProb, int *Delta_Pnt, int *Prob_Pnt, int *NewIndex_Y, 
				   short *Probability, int *ProbLocation, int BlocksMapIndex, int BMStep, BYTE *BlocksMap)
{
	int x, Pos, RealX=0;

	if (MinProb==0) {
    //______________
#ifdef _MMX1_

		INTEL_SetProb_BaseY(Top, Bottom, Cnt, &Probability[*Delta_Pnt], NewIndex_Y); 
		*Delta_Pnt+=Cnt;
#else

		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_Y_MVector(*Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], Delta_Pnt, *Prob_Pnt, NewIndex_Y,
							  	Probability, ProbLocation); 
		Top++; Bottom++; RealX+= BMStep; *Prob_Pnt +=1;
	
		for (x=1; x<(Cnt-1); x++, Top++, Bottom++, RealX += BMStep, *Prob_Pnt +=1) {
			Pos = BlocksMapIndex +( RealX>>3); 
			if (!GetBit(BlocksMap, Pos)) 
				SetProbability_Y_MVector(*Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], Delta_Pnt, *Prob_Pnt, 
				                         NewIndex_Y, Probability, ProbLocation); 
		}


		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_Y_MVector(*Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, Delta_Pnt, *Prob_Pnt, NewIndex_Y,
							  	Probability, ProbLocation); 
		*Prob_Pnt +=1;
#endif

	} else {
   //______________

#ifdef _MMX1_

		INTEL_SetProb_BaseY_MinProb(Top, Bottom, Cnt, &Probability[*Delta_Pnt], 
			                         &ProbLocation[*Delta_Pnt], MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_Y);
		*Prob_Pnt+=Cnt;
#else

		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_YLevel1(*Top, *Bottom, *Top, *Bottom, Top[1], Bottom[1], MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_Y,
							  	Probability, ProbLocation); 
		Top++; Bottom++; RealX += BMStep; *Prob_Pnt +=1;
	
		for (x=1; x<(Cnt-1); x++, Top++, Bottom++, RealX += BMStep, *Prob_Pnt +=1) {
			Pos = BlocksMapIndex +( RealX>>3); 
			if (!GetBit(BlocksMap, Pos)) 
				SetProbability_YLevel1(*Top, *Bottom, Top[-1], Bottom[-1], Top[1], Bottom[1], MinProb, Delta_Pnt, 
									*Prob_Pnt, NewIndex_Y, Probability, ProbLocation);
		}

		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_YLevel1(*Top, *Bottom, Top[-1], Bottom[-1], *Top, *Bottom, MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_Y,
			                   Probability, ProbLocation);
		*Prob_Pnt +=1;

#endif

	}
}


void Restore_BaseY(BYTE *dest, BYTE *Top, BYTE *Bottom, int Cnt, short *Quant_Rev, int MinProb, int *Delta_Pnt, 
				   int *Prob_Pnt, int *NewIndex_Y, char *QuantDelta, short *Probability, int *ProbLocation)
{
	int x, P;


#ifdef	_MMX_
		INTEL_Aver_Line(dest, Top, Bottom, Cnt);
#else
		for (x=0; x<Cnt; x++) dest[x] = ((int) (*Top++) + (int) (*Bottom++) + 1)>>1;
#endif


	if (MinProb==0) {
		for (x=0; x<Cnt; x++, dest++) {
			P = Probability[*Delta_Pnt];
			*Delta_Pnt+=1;
			*dest = CLIP(Quant_Rev[QuantDelta[NewIndex_Y[P]]]+(short) (*dest)); 
			NewIndex_Y[P]+=1;
		}
	} else {

		
		x = ProbLocation[*Delta_Pnt]-*Prob_Pnt;
		while (x<Cnt) {
			P = Probability[*Delta_Pnt];
			*Delta_Pnt+=1;
			dest[x] = CLIP(Quant_Rev[QuantDelta[NewIndex_Y[P]]]+dest[x]); 
			NewIndex_Y[P]+=1;
			x = ProbLocation[*Delta_Pnt]-*Prob_Pnt;
		}
		*Prob_Pnt+=Cnt;


	}
		
}

void Restore_BaseY_MVector(BYTE *dest, BYTE *Top, BYTE *Bottom, int Cnt, short *Quant_Rev, int *Delta_Pnt, 
				   int *Prob_Pnt, int *NewIndex_Y, char *QuantDelta, short *Probability, int *ProbLocation,
				   int BlocksMapIndex, int BMStep, BYTE *BlocksMap, BYTE *sorc)
{
	int x, P, Pos, RealX=0;


#ifdef	_MMX1_
		INTEL_Aver_Line(dest, Top, Bottom, Cnt);
#else
		for (x=0; x<Cnt; x++, RealX += BMStep, sorc+=2, Top++, Bottom++) {
			Pos = BlocksMapIndex +( RealX>>3); 
			if (!GetBit(BlocksMap, Pos)) 
				dest[x] = ((int) (*Top) + (int) (*Bottom) + 1)>>1;
			else
				dest[x] = *sorc;
		}
#endif



		
		x = ProbLocation[*Delta_Pnt]-*Prob_Pnt;
		while (x<Cnt) {
			P = Probability[*Delta_Pnt];
			*Delta_Pnt+=1;
			dest[x] = CLIP(Quant_Rev[QuantDelta[NewIndex_Y[P]]]+dest[x]); 
			NewIndex_Y[P]+=1;
			x = ProbLocation[*Delta_Pnt]-*Prob_Pnt;
		}
		*Prob_Pnt+=Cnt;


		
}



INLINE void SetProbability_X(BYTE *dest, int Base1, int Base2, int N1, int N2, int N3, int N4, int *Delta_Pnt, 
							 int *NewIndex_X, short *Probability)
{
	int BB, Pr;

	BB = Base1+Base2;
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	Probability[*Delta_Pnt] = Pr;
	*Delta_Pnt +=1; 
	*dest =(BB+1)>>1;
	NewIndex_X[Pr]+=1;

}

INLINE void SetProbability_XLevel0(BYTE *dest, int Base1, int Base2, int N1, int N2, int N3, int N4, int MinProb,
								   int *Delta_Pnt, int Prob_Pnt, int *NewIndex_X, short *Probability, int *ProbLocation)
{
	int BB, Pr;

	BB = Base1+Base2;
	
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	*dest =(BB+1)>>1;
	if (Pr>=MinProb) {
		ProbLocation[*Delta_Pnt] = Prob_Pnt;
		Probability[*Delta_Pnt]= Pr;
		*Delta_Pnt +=1; 
		NewIndex_X[Pr] += 1;
	}		
	
}


INLINE void SetProbability_X_MVector(BYTE *dest, int Base1, int Base2, int N1, int N2, int N3, int N4, 
								   int *Delta_Pnt, int Prob_Pnt, int *NewIndex_X, short *Probability, int *ProbLocation)
{
	int BB, Pr;

	BB = Base1+Base2;
	
	Pr= abs(Base1 - Base2) * 8 + abs(BB - N1 * 2) + abs(BB - N2 * 2) + abs(BB - N3 * 2) + abs(BB - N4 * 2);
	*dest =(BB+1)>>1;
	
		ProbLocation[*Delta_Pnt] = Prob_Pnt;
		Probability[*Delta_Pnt]= Pr;
		*Delta_Pnt +=1; 
		NewIndex_X[Pr] += 1;
			
	
}


void SetProb_BaseX(BYTE *RESTRICT dest, BYTE *RESTRICT Top, BYTE *RESTRICT Center, BYTE *RESTRICT Bottom, int W, int MinProb,
				   int *Delta_Pnt, int *Prob_Pnt, int *NewIndex_X, short *Probability, int *ProbLocation)
{
	int x;

if (MinProb==0) {
//_______________

#ifdef _MMX_

		INTEL_SetProb_BaseX(dest, Top, Center, Bottom, W, &Probability[*Delta_Pnt], NewIndex_X); 
		*Delta_Pnt+=W>>1;
#else
	for (x=2; x<W; x+=2, Top++, Center++, Bottom++, dest+=2) {
		*dest = *Center;

		SetProbability_X(dest+1, *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], Delta_Pnt, NewIndex_X, Probability); 
	}	

	*dest = *Center;
	if ((x-1)<W) SetProbability_X(dest+1, *Center, *Center, *Top, *Top, *Bottom, *Bottom, Delta_Pnt, NewIndex_X, Probability);

#endif

} else {
//______________

#ifdef _MMX_

		INTEL_SetProb_BaseX_MinProb(dest, Top, Center, Bottom, W, &Probability[*Delta_Pnt], 
			                         &ProbLocation[*Delta_Pnt], MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_X);
		*Prob_Pnt+=W>>1;
#else

	for (x=2; x<W; x+=2, Top++, Center++, Bottom++, dest+=2, *Prob_Pnt+=1) {
		*dest = *Center;

		SetProbability_XLevel0(dest+1, *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], MinProb, Delta_Pnt, 
			                   *Prob_Pnt, NewIndex_X, Probability, ProbLocation); 
	}	

	*dest = *Center;
	if ((x-1)<W) {
		SetProbability_XLevel0(dest+1, *Center, *Center, *Top, *Top, *Bottom, *Bottom, MinProb, Delta_Pnt,
		                                *Prob_Pnt, NewIndex_X, Probability, ProbLocation);
		*Prob_Pnt+=1;
	}	
#endif
}
}

void SetProb_BaseX_MVector(BYTE *RESTRICT dest, BYTE *RESTRICT Top, BYTE *RESTRICT Center, BYTE *RESTRICT Bottom, int W, 
				   int MinProb, int *Delta_Pnt, int *Prob_Pnt, int *NewIndex_X, short *Probability, int *ProbLocation,
				   int BlocksMapIndex, int BMStep, BYTE *BlocksMap)
{
	int x, Pos, RealX=BMStep/2;

if (MinProb==0) {
//_______________

#ifdef _MMX1_

		INTEL_SetProb_BaseX(dest, Top, Center, Bottom, W, &Probability[*Delta_Pnt], NewIndex_X); 
		*Delta_Pnt+=W>>1;
#else
	for (x=2; x<W; x+=2, Top++, Center++, Bottom++, dest+=2, RealX += BMStep, *Prob_Pnt+=1) {
		*dest = *Center;

		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_X_MVector(dest+1, *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], Delta_Pnt, 
			                   *Prob_Pnt, NewIndex_X, Probability, ProbLocation); 
			
	}	

	*dest = *Center;
	if ((x-1)<W) {
		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_X_MVector(dest+1, *Center, *Center, *Top, *Top, *Bottom, *Bottom, Delta_Pnt, 
			                   *Prob_Pnt, NewIndex_X, Probability, ProbLocation); 
		*Prob_Pnt+=1;
	}	
#endif

} else {
//______________

#ifdef _MMX1_

		INTEL_SetProb_BaseX_MinProb(dest, Top, Center, Bottom, W, &Probability[*Delta_Pnt], 
			                         &ProbLocation[*Delta_Pnt], MinProb, Delta_Pnt, *Prob_Pnt, NewIndex_X);
		*Prob_Pnt+=W>>1;
#else

	for (x=2; x<W; x+=2, Top++, Center++, Bottom++, dest+=2, RealX += BMStep, *Prob_Pnt+=1) {
		*dest = *Center;

		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_XLevel0(dest+1, *Center, Center[1], *Top, Top[1], *Bottom, Bottom[1], MinProb, Delta_Pnt, 
			                   *Prob_Pnt, NewIndex_X, Probability, ProbLocation); 
	}	

	*dest = *Center;
	if ((x-1)<W) {
		Pos = BlocksMapIndex +( RealX>>3); 
		if (!GetBit(BlocksMap, Pos)) 
			SetProbability_XLevel0(dest+1, *Center, *Center, *Top, *Top, *Bottom, *Bottom, MinProb, Delta_Pnt,
		                                *Prob_Pnt, NewIndex_X, Probability, ProbLocation);
		*Prob_Pnt+=1;
	}	
#endif
}
}


void Restore_BaseX(BYTE *dest, int W, short *Quant_Rev, char *QuantDelta, int MinProb, int *Delta_Pnt, 
				   int *Prob_Pnt, int *NewIndex_X, short *Probability, int *ProbLocation)
{
	int x, P;

if (MinProb==0) {
	dest++;
	for (x=1; x<W; x+=2, dest+=2) {
		P = Probability[*Delta_Pnt];
		*Delta_Pnt +=1;
		*dest = CLIP(Quant_Rev[QuantDelta[NewIndex_X[P]]]+*dest); 
		NewIndex_X[P]+=1;
	}	
} else {

	x = ((ProbLocation[*Delta_Pnt]-*Prob_Pnt)<<1)+1;
	while (x<W) {
		P = Probability[*Delta_Pnt];
		*Delta_Pnt +=1;
		dest[x] = CLIP(Quant_Rev[QuantDelta[NewIndex_X[P]]]+dest[x]); 
		NewIndex_X[P]+=1;
		x = ((ProbLocation[*Delta_Pnt]-*Prob_Pnt)<<1)+1;
	}
	*Prob_Pnt+=W>>1;



}
}

/*______________________________________________________________________________________________________________


						Decompress_Level

_______________________________________________________________________________________________________________*/

void Decompress_Level(BYTE * buf, BYTE *QuartBuf, int W, int H, BYTE * Pool, int *Start, int Level, BYTE *Memory,
					  int QUART)
{
	int y, i, hH, hW, DPX, DPY, Qx, Qy, Qshift, MaxProb_Y, MaxProb_X, MinPY, MinPX, PPX, PPY, DPXo;
	BYTE	*PB, *QB, *LL; 

	int	*NewIndex_X		= (int*)   DECODER_MEMORY_GET_ADDRESS(ID_DECODER_NewIndex_X,   Memory);
	int	*NewIndex_Y		= (int*)   DECODER_MEMORY_GET_ADDRESS(ID_DECODER_NewIndex_Y,   Memory);
	char *QuantDelta	= (char*)  DECODER_MEMORY_GET_ADDRESS(ID_DECODER_QuantDelta,   Memory);
	short *Probability	= (short*) DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Probability,  Memory);
	int *ProbLocation   = (int*)   DECODER_MEMORY_GET_ADDRESS(ID_DECODER_ProbLocation, Memory);
	BYTE *L1			=          DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Temp_Line1,   Memory); 
	BYTE *L2			=          DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Temp_Line2,   Memory); 


	if ((H <= StopSize) || (W <= StopSize)) {
		for (i = 0; i<H*W; i++) buf[i] = GetNumber(0xFF, Pool, Start);
		return;
	}
	


	hH = (H+1)>>1; hW = (W+1)>>1;
	QB = QuartBuf+hH*hW;
	if (QUART)  {
		Decompress_Level(buf, QB, hW, hH, Pool, Start, Level+2, Memory, 0);
		return;
	}
	Decompress_Level(QuartBuf, QB, hW, hH, Pool, Start, Level+2, Memory, 0);

	QB = QuartBuf;
	DPY = 0; PPY=0;
	Qy = GetNumber(MaxQ, Pool, Start);
	
	if (Level==0) MinPY = MinProbability(Qy); else MinPY=0;
	for (y=1; y<H; y+=2, QB+=hW) {		
		if ((y+1)<H) SetProb_BaseY(QB, QB+hW, hW, MinPY, &DPY, &PPY, NewIndex_Y, Probability, ProbLocation); 
		else SetProb_BaseY(QB, QB, hW, MinPY, &DPY, &PPY, NewIndex_Y, Probability, ProbLocation);
	}


	MaxProb_Y = 0;
	if (DPY>0) Unpack_Deltas(QuantDelta, DPY, Qy, Pool, Start, &MaxProb_Y, NewIndex_Y, Memory);		// Y-Base		
	Qshift = (Qy<<9)+255;

	Qx = GetNumber(MaxQ, Pool, Start);
	
	if (Level==0) MinPX = MinProbability(Qx); else MinPX=0;

	ProbLocation[DPY++] = 0x1FFFFFFF;
	DPXo = DPY; DPX= DPXo; DPY=0; 
	PPX = 0; PPY=0;
	QB = QuartBuf; PB = buf;
	for (y=0; y<H; y+=2, PB+=W*2, QB+=hW) {
		
		if ((y+1)<H) {
			
			if ((y+2)<H) Restore_BaseY(L2, QB, QB+hW, hW, Quantum_Rev+Qshift, MinPY, &DPY, &PPY, NewIndex_Y,
				                       QuantDelta, Probability, ProbLocation); 
			        else Restore_BaseY(L2, QB, QB,    hW, Quantum_Rev+Qshift, MinPY, &DPY, &PPY, NewIndex_Y,
						               QuantDelta, Probability, ProbLocation);
		}

		if (y==0) SetProb_BaseX(PB, QB, QB, L2, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation); 
		else { 
			if ((y+1)<H) SetProb_BaseX(PB, L1, QB, L2, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation);
			else SetProb_BaseX(PB, L1, QB, QB, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation);
		}

		if ((y+1)<H) {
			if ((y+2)<H) SetProb_BaseX(PB+W, QB, L2, QB+hW, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation); 
			        else SetProb_BaseX(PB+W, QB, L2, L2,    W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation);	
		}
		
		LL = L1; L1 = L2; L2 = LL; // swap L1<->L2
	}


	MaxProb_X = 0;
	if ((DPX-DPXo)>0) Unpack_Deltas(&QuantDelta[DPXo], DPX-DPXo, Qx, Pool, Start, &MaxProb_X, NewIndex_X, Memory);	// X-Base		
	
	Qshift = (Qx<<9)+255;

	ProbLocation[DPX] = 0x1FFFFFFF;
	PB = buf; DPX = DPXo; PPX = 0;
	for (y=0; y<H; y++, PB+=W) Restore_BaseX(PB, W, Quantum_Rev+Qshift, QuantDelta+DPXo, MinPX, &DPX, &PPX, NewIndex_X,
		                                     Probability, ProbLocation);	
	
	if (MaxProb_Y>0) memset(NewIndex_Y,0,sizeof(int)*(MaxProb_Y));
	if (MaxProb_X>0) memset(NewIndex_X,0,sizeof(int)*(MaxProb_X));


}


/*______________________________________________________________________________________________________________


						Decompress_Level_MVector

_______________________________________________________________________________________________________________*/
#ifdef _MVECTOR_

void Decompress_Level_MVector(BYTE * buf, BYTE *QuartBuf, int W, int Wo, int H, BYTE * Pool, int *Start, int Level, 
							  BYTE *Memory)
{
	int y, x, i, hH, hW, DPX, DPY, Qx, Qy, Qshift, MaxProb_Y, MaxProb_X, MinPY, MinPX, PPX, PPY, DPXo;
	BYTE	*PB, *QB, *LL; 
	int BlocksMapPnt, BMStep, Pos, RealX;

	int	*NewIndex_X		= (int*)   DECODER_MEMORY_GET_ADDRESS(ID_DECODER_NewIndex_X,   Memory);
	int	*NewIndex_Y		= (int*)   DECODER_MEMORY_GET_ADDRESS(ID_DECODER_NewIndex_Y,   Memory);
	char *QuantDelta	= (char*)  DECODER_MEMORY_GET_ADDRESS(ID_DECODER_QuantDelta,   Memory);
	short *Probability	= (short*) DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Probability,  Memory);
	int *ProbLocation   = (int*)   DECODER_MEMORY_GET_ADDRESS(ID_DECODER_ProbLocation, Memory);
	BYTE *L1			=          DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Temp_Line1,   Memory); 
	BYTE *L2			=          DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Temp_Line2,   Memory); 


	if ((H <= StopSize) || (W <= StopSize)) {
		for (y=0; y<H; y++) {
			BMStep = 1<<(Level>>1); BlocksMapPnt = ((y<<(Level>>1))>>3)*((Wo+7)>>3); 
			RealX=0;
			for (x=0; x<W; x++, RealX+=BMStep, buf++) {

				Pos = BlocksMapPnt +( RealX>>3); 
				if (!GetBit(BlocksMap, Pos)) *buf = GetNumber(0xFF, Pool, Start);


			}

		}
		return;
	}
	
	QB = QuartBuf;
	hH = (H+1)>>1; hW = (W+1)>>1;
	for (y=0; y<H; y+=2) {
		PB = buf+W*y; 
		for (x=0; x<hW; x++, PB+=2) *QB++ = *PB; 
	}
	Decompress_Level_MVector(QuartBuf, QB, hW, Wo, hH, Pool, Start, Level+2, Memory);

	QB = QuartBuf;
	DPY = 0; PPY=0;
	Qy = GetNumber(MaxQ, Pool, Start);
	
	if (Level==0) MinPY = MinProbability(Qy); else MinPY=0;
	for (y=1; y<H; y+=2, QB+=hW) {		
		// Odd y
		BMStep = 2<<(Level>>1); BlocksMapPnt = ((y<<(Level>>1))>>3)*((Wo+7)>>3);
		if ((y+1)<H) SetProb_BaseY_MVector(QB, QB+hW, hW, MinPY, &DPY, &PPY, NewIndex_Y, Probability, ProbLocation, 
			                               BlocksMapPnt, BMStep, BlocksMap); 
		else SetProb_BaseY_MVector(QB, QB, hW, MinPY, &DPY, &PPY, NewIndex_Y, Probability, ProbLocation, 
			                       BlocksMapPnt, BMStep, BlocksMap);
	}


	MaxProb_Y = 0;
	if (DPY>0) Unpack_Deltas(QuantDelta, DPY, Qy, Pool, Start, &MaxProb_Y, NewIndex_Y, Memory);		// Y-Base		
	Qshift = (Qy<<9)+255;

	Qx = GetNumber(MaxQ, Pool, Start);
	
	if (Level==0) MinPX = MinProbability(Qx); else MinPX=0;

	ProbLocation[DPY++] = 0x1FFFFFFF;
	DPXo = DPY; DPX= DPXo; DPY=0; 
	PPX = 0; PPY=0;
	QB = QuartBuf; PB = buf;
	for (y=0; y<H; y+=2, PB+=W*2, QB+=hW) {
		
		if ((y+1)<H) {
			
			// Odd y
			BMStep = 2<<(Level>>1); BlocksMapPnt = (((y+1)<<(Level>>1))>>3)*((Wo+7)>>3);
			if ((y+2)<H) Restore_BaseY_MVector(L2, QB, QB+hW, hW, Quantum_Rev+Qshift, &DPY, &PPY, NewIndex_Y,
				                       QuantDelta, Probability, ProbLocation, BlocksMapPnt, BMStep, BlocksMap, PB+W); 
			        else Restore_BaseY_MVector(L2, QB, QB,    hW, Quantum_Rev+Qshift, &DPY, &PPY, NewIndex_Y,
						               QuantDelta, Probability, ProbLocation, BlocksMapPnt, BMStep, BlocksMap, PB+W);
		}

		// Even y - Odd x
		BMStep = 2<<(Level>>1); BlocksMapPnt = ((y<<(Level>>1))>>3)*((Wo+7)>>3); 

		if (y==0) SetProb_BaseX_MVector(PB, QB, QB, L2, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation,
										BlocksMapPnt, BMStep, BlocksMap); 
		else { 
			if ((y+1)<H) SetProb_BaseX_MVector(PB, L1, QB, L2, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, 
											   ProbLocation, BlocksMapPnt, BMStep, BlocksMap);
			else SetProb_BaseX_MVector(PB, L1, QB, QB, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, ProbLocation,
										BlocksMapPnt, BMStep, BlocksMap);
		}

		// Odd y - Odd x
		BMStep = 2<<(Level>>1); BlocksMapPnt = (((y+1)<<(Level>>1))>>3)*((Wo+7)>>3);
		if ((y+1)<H) {
			if ((y+2)<H) SetProb_BaseX_MVector(PB+W, QB, L2, QB+hW, W, MinPX, &DPX, &PPX, NewIndex_X, Probability, 
												ProbLocation, BlocksMapPnt, BMStep, BlocksMap); 
			        else SetProb_BaseX_MVector(PB+W, QB, L2, L2,    W, MinPX, &DPX, &PPX, NewIndex_X, Probability, 
												ProbLocation, BlocksMapPnt, BMStep, BlocksMap);	
		}
		
		LL = L1; L1 = L2; L2 = LL; // swap L1<->L2
	}


	MaxProb_X = 0;
	if ((DPX-DPXo)>0) Unpack_Deltas(&QuantDelta[DPXo], DPX-DPXo, Qx, Pool, Start, &MaxProb_X, NewIndex_X, Memory);	// X-Base		
	
	Qshift = (Qx<<9)+255;

	ProbLocation[DPX] = 0x1FFFFFFF;
	PB = buf; DPX = DPXo; PPX = 0;
	for (y=0; y<H; y++, PB+=W) Restore_BaseX(PB, W, Quantum_Rev+Qshift, QuantDelta+DPXo, 1, &DPX, &PPX, NewIndex_X,
		                                     Probability, ProbLocation);	
	
	if (MaxProb_Y>0) memset(NewIndex_Y,0,sizeof(int)*(MaxProb_Y));
	if (MaxProb_X>0) memset(NewIndex_X,0,sizeof(int)*(MaxProb_X));


}
#endif


void Decompress_Entry(BYTE *buf, BYTE *QuartBuf, int W, int H, BYTE *Pool, int *Start, BYTE *Memory, int BufType, 
					  int QUART)
{
	int Start0 = *Start;
	BYTE *PrevBuf;

#ifdef _MVECTOR_

	if (BufType==0) PrevBuf = IBufferY_dec; 
	if (BufType==1) PrevBuf = IBufferU_dec; 
	if (BufType==2) PrevBuf = IBufferV_dec;


	if (FrameCounter==0) {
		
		Decompress_Level(buf, QuartBuf, W, H, Pool, Start, 0, Memory);
		memcpy(PrevBuf, buf, W*H);
	
	} else {
	
		Insert_Blocks(PrevBuf, buf, W, H, Pool, Start, Memory);
		Decompress_Level_MVector(buf, QuartBuf, W, W, H, Pool, Start, 0, Memory);
		memcpy(PrevBuf, buf, W*H);

	}	
	 


#else


	Decompress_Level(buf, QuartBuf, W, H, Pool, Start, 0, Memory, QUART);


#endif	

}


void Decompress_UV(BYTE *buf, BYTE *QuartBuf, int W, int H, BYTE *Pool, int *Start, BYTE *Memory, int BufType, 
				   int QUART)
{
	int x, y, A;
	BYTE *P, *T;

	T = QuartBuf+W*(H/2);
	Decompress_Entry(QuartBuf, T, W, H/2, Pool, Start, Memory, BufType, QUART);

	if (QUART) { W/=2; H/=2; }


	T = QuartBuf;
	for (y = 0; y<(H-1); y+=2) {
		P = buf+y*W;
		for (x = 0; x<W; x++, P++) {
			A = *T++; 
			*P = A; P[W] = A;
		}
	}

}





void DECOMPRESS_FRAME(BYTE *Ybuf, BYTE *Ubuf, BYTE *Vbuf, int W, int H, BYTE *Pool, BYTE *Memory)
{

	int Pool_index;

	BYTE *Quart_Buffer = DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Quart_Buffer, Memory);

	Pool_index = 0;

	Decompress_Entry(Ybuf, Quart_Buffer, W,   H, Pool, &Pool_index, Memory, 0, 0); 

	Decompress_UV(Ubuf, Quart_Buffer, W/2, H, Pool, &Pool_index, Memory, 1, 0); 

	Decompress_UV(Vbuf, Quart_Buffer, W/2, H, Pool, &Pool_index, Memory, 2, 0); 



#ifdef _MVECTOR_
	FrameCounter = (FrameCounter+1) % MaxFrameCounter;
#endif
}



void Squeeze(BYTE *Sorc, int W, int H)
{
	int y, x;
	BYTE *Dest;
	
	Dest = Sorc;
	
	for (y=0; y<H; y+=2, Sorc+=W) for (x=0; x<W; x+=2, Sorc+=2) *Dest++ = *Sorc;	

}



void DECOMPRESS_QUART_FRAME(BYTE *Ybuf, BYTE *Ubuf, BYTE *Vbuf, int W, int H, BYTE *Pool, BYTE *Memory, int PoolLen)
{

	int Pool_index0, Pool_index1, Pool_index2;


	BYTE *Quart_Buffer = DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Quart_Buffer, Memory);


	if (PoolLen==0) {
		DECOMPRESS_FRAME(Ybuf, Ubuf, Vbuf, W, H, Pool, Memory);

		Squeeze(Ybuf, W,   H);
		Squeeze(Ubuf, W/2, H);
		Squeeze(Vbuf, W/2, H);

	} else {

		PoolLen = (PoolLen<<3) - 48;
		Pool_index0 = 0;
		Pool_index1 = Get24(Pool, &PoolLen);
		Pool_index2 = Get24(Pool, &PoolLen);

		Decompress_Entry(Ybuf, Quart_Buffer, W,   H, Pool, &Pool_index0, Memory, 0, 1); 

		Decompress_UV(Ubuf, Quart_Buffer, W/2, H, Pool, &Pool_index1, Memory, 1, 1); 

		Decompress_UV(Vbuf, Quart_Buffer, W/2, H, Pool, &Pool_index2, Memory, 2, 1); 
	}

}



